桌面程序文字绘制 – Windows API

最近更新于 2024-05-05 14:18

环境

Windows 11 专业工作站版 22H2
Visual Studio 2022 专业版

使用 Unicode 字符集,C17 标准编译,64 位编译

文字绘制(颜色、背景透明、背景色)

#include <Windows.h>

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_PAINT:
        {
            PAINTSTRUCT ps = {0};
            HDC hdc = BeginPaint(hWnd, &ps);
            COLORREF oldColor = SetTextColor(hdc, RGB(255, 0, 0)); // 文字颜色设为红色,并保存原来的颜色
            // 文字绘制方式 1
            // DC 句柄
            // 文字行左上角坐标 x
            // 文字行左上角坐标 y
            // 显示文字内容
            // 文字内容的长度
            TextOut(hdc, 200, 50, L"你好啊!", wcslen(L"你好啊!"));
            RECT rect1 = {10, 10, 50, 200}; // 矩形结构,左上角坐标和右下角坐标
            SetBkMode(hdc, TRANSPARENT); // 设置文字显示背景透明,透明状态下,设置文字背景色无效,不透明是默认状态
            // 文字绘制方式 2
            // DC 句柄
            // 显示文字内容
            // 文字内容长度
            // 绘制文字的矩形区域
            // 文字显示格式,比如这里 DT_LEFT 靠左,DT_WORDBREAK 在行显示满时支持换行继续显示,DT_NOCLIP 支持在行显示单词超出矩形区域时依然完整显示,不剪裁
            DrawText(hdc, L"DrawText ABC 文字输出", wcslen(L"DrawText ABC 文字输出"), &rect1, DT_LEFT | DT_WORDBREAK | DT_NOCLIP);
            RECT rect2 = {100, 100, 140, 200};
            SetTextColor(hdc, oldColor); // 改回默认的字体颜色
            SetBkMode(hdc, OPAQUE); // 设置文字显示背景不透明
            SetBkColor(hdc, RGB(0, 0, 255)); // 背景色设为蓝色
            DrawText(hdc, L"DrawText ABC 文字输出", wcslen(L"DrawText ABC 文字输出"), &rect2, DT_LEFT | DT_WORDBREAK);
            EndPaint(hWnd, &ps);
            break;
        }
        case WM_CLOSE:
        {
            DestroyWindow(hWnd);
            break;
        }
        case WM_DESTROY:
        {
            PostQuitMessage(0);
            break;
        }
        default:
        {
            return DefWindowProc(hWnd, msg, wParam, lParam);
        }
    }
    return 0;
}

int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPreInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
    PCWSTR szClassName = L"Desktop";
    WNDCLASSEX wc = {0};
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.lpszClassName = szClassName;
    wc.lpfnWndProc = WndProc;
    if (!RegisterClassEx(&wc))
    {
        MessageBox(NULL, L"注册窗口失败!", L"错误", MB_OK);
        return 1;
    }

    HWND hWnd = CreateWindowEx(0, szClassName, L"简单程序", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, NULL, NULL, hInstance, NULL);
    if (!hWnd)
    {
        MessageBox(NULL, L"创建窗口失败!", L"错误", MB_OK);
        return 1;
    }

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    MSG msg = {0};
    while (GetMessage(&msg, NULL, 0, 0))
    {
        DispatchMessage(&msg);
    }

    return (int)msg.wParam;
}

file

字体

系统字体保存在 C:\Windows\Fonts
使用字体时要用到字体的名字,注意字体的名字并不一定是文件名
file

需要将字体文件直接打开,预览页面上会显示字体的名字
比如这个文件名叫新宋体,但是字体的名字就叫宋体
file

#include <Windows.h>

HFONT g_hFont = {0}; // 字体句柄。

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_PAINT:
        {
            PAINTSTRUCT ps = {0};
            HDC hdc = BeginPaint(hWnd, &ps);
            HGDIOBJ hOldFont =  SelectObject(hdc, g_hFont); // 切换使用加载的字体
            TextOut(hdc, 70, 120, L"你好啊 ABC 123", wcslen( L"你好啊 ABC 123"));
            SelectObject(hdc, hOldFont); // 换回默认的字体
            EndPaint(hWnd, &ps);
            break;
        }
        case WM_CLOSE:
        {
            DestroyWindow(hWnd);
            break;
        }
        case WM_DESTROY:
        {
            PostQuitMessage(0);
            DeleteObject(g_hFont); // 销毁字体资源
            break;
        }
        default:
        {
            return DefWindowProc(hWnd, msg, wParam, lParam);
        }
    }
    return 0;
}

int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPreInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
    // 创建字体句柄 - 字体比较大放到窗口过程的话,一直调用消耗资源大,放到全局变量只用加载一次
     g_hFont = CreateFont(0, // 字体高度,指定 0 按照默认处理
                          0, // 字体宽度,指定 0 按照默认处理
                          300, // 转义向量与设备的 x 轴之间的角度(单位为 0.1°,下同),转义向量与文本行的基线并行
                          0, // 每个字符的基线与设备的 x 轴之间的角度
                          FW_NORMAL, // 字体粗细,取值 0~100,400 正常,700 为粗体,设 0 为默认(FW_NORMAL)。有定义宏,可以参考开发文档
                          FALSE, // 是否斜体
                          TRUE, // 是否有下划线
                          FALSE, // 是否有删除线
                          GB2312_CHARSET, // 字符集 - 这里使用 GB2312_CHARSET(Windows 中文使用的字符集)
                          OUT_CHARACTER_PRECIS, // 输出精度,OUT_CHARACTER_PRECIS 未使用
                          CLIP_CHARACTER_PRECIS, // 剪裁精度, CLIP_CHARACTER_PRECIS 未使用
                          CLEARTYPE_QUALITY, // 输出质量,比如 CLEARTYPE_QUALITY 尽可能使用 ClearType 抗锯齿方法,NONANTIALIASED_QUALITY 不抗锯齿,不平滑字体
                          DEFAULT_PITCH | FF_DONTCARE, // 字体的音调和系列,DEFAULT_PITCH | FF_DONTCARE 都默认
                          L"华文琥珀"); // 字体名字

    PCWSTR szClassName = L"Desktop";
    WNDCLASSEX wc = {0};
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.lpszClassName = szClassName;
    wc.lpfnWndProc = WndProc;
    if (!RegisterClassEx(&wc))
    {
        MessageBox(NULL, L"注册窗口失败!", L"错误", MB_OK);
        return 1;
    }

    HWND hWnd = CreateWindowEx(0, szClassName, L"简单程序", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, NULL, NULL, hInstance, NULL);
    if (!hWnd)
    {
        MessageBox(NULL, L"创建窗口失败!", L"错误", MB_OK);
        return 1;
    }

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    MSG msg = {0};
    while (GetMessage(&msg, NULL, 0, 0))
    {
        DispatchMessage(&msg);
    }

    return (int)msg.wParam;
}

file

桌面程序文字绘制 – Windows API
Scroll to top